package com.douwong.student.utils;


import com.douwong.student.application.BaseApplication;
import com.douwong.student.contant.Config;
import com.douwong.student.view.ProgressInputStream;

import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;

public class FtpUtils {
	private static final String TAG = "FtpUtils";
	/**
	 * 服务器名.
	 */
	private   String hostName;

	/**
	 * 端口号
	 */
	private   int serverPort;

	/**
	 * 用户名.
	 */
	private  String userName;

	/**
	 * 密码.
	 */
	private  String password;

	/**
	 * FTP连接.
	 */
	private FTPClient ftpClient;
	private long mLasttime;
	private long mLastSize;
	private  int defaultTimeoutSecond =20;

	public FtpUtils() {
		hostName = BaseApplication.sFtpInfo.ftpUrl;
		serverPort = 21;
		userName = BaseApplication.sFtpInfo.ftpName;
		password = BaseApplication.sFtpInfo.ftpPass;
		ftpClient=new FTPClient();
		ftpClient.setDefaultTimeout(defaultTimeoutSecond * 1000);
		ftpClient.setConnectTimeout(defaultTimeoutSecond * 1000);
		ftpClient.setDataTimeout(defaultTimeoutSecond * 1000);

	}

	// -------------------------------------------------------文件上传方法------------------------------------------------

	/**
	 * 上传多个文件.
	 *
	 * @param fileList
	 *            本地文件
	 * @param remotePath
	 *            FTP目录
	 * @param listener
	 *            监听器
	 * @throws IOException
	 */
	public void uploadMultiFile(LinkedList<File> fileList, String remotePath,
			UploadProgressListener listener) throws Exception {

		// 上传之前初始化
		this.uploadBeforeOperate(remotePath, listener);

		boolean flag;
		for (File singleFile : fileList) {
			flag = uploadingSingle(singleFile, listener);
			if (flag) {
				listener.onUploadProgress(Config.FTP_UPLOAD_SUCCESS, 0,
						singleFile);
				LogUtils.i(TAG,"上传成功");
			} else {
				listener.onUploadProgress(Config.FTP_UPLOAD_FAIL, 0,
						singleFile);
				LogUtils.i(TAG,"上传失败");
			}
		}


		// 上传完成之后关闭连接
		this.uploadAfterOperate(listener);
	}

	/**
	 * 上传单个文件.
	 *
	 * @param singleFile
	 *            本地文件
	 * @param remotePath
	 *            FTP目录
	 * @param listener
	 *            监听器
	 * @throws IOException
	 */
	public void uploadSingleFile(File singleFile, String remotePath,
								 UploadProgressListener listener) throws Exception {

		// 上传之前初始化
		this.uploadBeforeOperate(remotePath, listener);

		boolean flag;
		flag = uploadingSingle(singleFile, listener);
		if (flag) {
			listener.onUploadProgress(Config.FTP_UPLOAD_SUCCESS, 0,
					singleFile);
		} else {
			listener.onUploadProgress(Config.FTP_UPLOAD_FAIL, 0,
					singleFile);
		}

		// 上传完成之后关闭连接
		this.uploadAfterOperate(listener);
	}
	/**
	 * 上传单个文件.
	 *
	 * @param singleFile
	 *            本地文件
	 * @param remotePath
	 *            FTP目录
	 * @param listener
	 *            监听器
	 * @throws IOException
	 */
	public void uploadSingleFile(File singleFile,String remotePath,String remoteFileName,
								 UploadProgressListener listener) throws Exception {

		// 上传之前初始化
		this.uploadBeforeOperate(remotePath, listener);

		boolean flag;
		flag = uploadingSingle(singleFile, remoteFileName,listener);
		if (flag) {
			listener.onUploadProgress(Config.FTP_UPLOAD_SUCCESS, 0,
					singleFile);
		} else {
			listener.onUploadProgress(Config.FTP_UPLOAD_FAIL, 0,
					singleFile);
		}

		// 上传完成之后关闭连接
		this.uploadAfterOperate(listener);
	}

	/**
	 * 上传单个文件.带文件名
	 * 
	 * @param localFile
	 *            本地文件
	 * @return true上传成功, false上传失败
	 * @throws IOException
	 */
	private boolean uploadingSingle(File localFile,
			UploadProgressListener listener) throws Exception {
		boolean flag = true;
		// 带有进度的方式
		BufferedInputStream buffIn = new BufferedInputStream(
				new FileInputStream(localFile));
		ProgressInputStream progressInput = new ProgressInputStream(buffIn,
				listener, localFile);
		flag = ftpClient.storeFile(localFile.getName(), progressInput);
		buffIn.close();
		progressInput.close();
		return flag;
	}/**
	 * 上传单个文件.带文件名
	 *
	 * @param localFile
	 *            本地文件
	 * @return true上传成功, false上传失败
	 * @throws IOException
	 */
	private boolean uploadingSingle(File localFile,String remonteFileName,
			UploadProgressListener listener) throws Exception {
		boolean flag ;
		// 带有进度的方式
		BufferedInputStream buffIn = new BufferedInputStream(
				new FileInputStream(localFile));
		ProgressInputStream progressInput = new ProgressInputStream(buffIn,
				listener, localFile);
		flag = ftpClient.storeFile(remonteFileName, progressInput);
		buffIn.close();
		progressInput.close();
		return flag;
	}
	
	/**
	 * 上传文件之前初始化相关参数
	 * 
	 * @param remotePath
	 *            FTP目录
	 * @param listener
	 *            监听器
	 * @throws IOException
	 */
	private void uploadBeforeOperate(String remotePath,
			UploadProgressListener listener) throws IOException {

		// 打开FTP服务
		try {
			this.openConnect();
			listener.onUploadProgress(Config.FTP_CONNECT_SUCCESSS, 0,
					null);
		} catch (IOException e1) {
			e1.printStackTrace();
			listener.onUploadProgress(Config.FTP_CONNECT_FAIL, 0, null);
			return;
		}
		//ftpClient.enterRemotePassiveMode();
			// 设置模式
		ftpClient.setFileTransferMode(org.apache.commons.net.ftp.FTP.STREAM_TRANSFER_MODE);
		/*遍历创建文件夹*/

		if (remotePath.contains("/")){
			String[] split = remotePath.split("/");
			for (int i = 0; i < split.length; i++) {
				ftpClient.makeDirectory(split[i]);
				ftpClient.changeWorkingDirectory(split[i]);
			}
		}
		/*end*/
		// FTP下创建文件夹
	//	boolean b = ftpClient.makeDirectory(remotePath);
	//	LogUtils.i(TAG,"创建文件夹"+b);

		// 改变FTP目录
		boolean bbb = ftpClient.changeWorkingDirectory(remotePath);
		LogUtils.i(TAG,"改变目录"+bbb);

		// 上传单个文件

	}

	/**
	 * 上传完成之后关闭连接
	 * 
	 * @param listener
	 * @throws IOException
	 */
	private void uploadAfterOperate(UploadProgressListener listener)
			throws IOException {
		this.closeConnect();
		listener.onUploadProgress(Config.FTP_DISCONNECT_SUCCESS, 0, null);
	}

	// -------------------------------------------------------文件下载方法------------------------------------------------

	/**
	 * 下载单个文件，可实现断点下载.
	 * 
	 * @param serverPath
	 *            Ftp目录及文件路径
	 * @param localPath
	 *            本地目录
	 * @param fileName       
	 *            下载之后的文件名称
	 * @param listener
	 *            监听器
	 * @throws IOException
	 */
	public void downloadSingleFile(String serverPath, String localPath, String fileName, DownLoadProgressListener listener)
			throws Exception {
		// 打开FTP服务
		try {
			this.openConnect();
			listener.onDownLoadProgress(Config.FTP_CONNECT_SUCCESSS, 0, null);
		} catch (IOException e1) {
			e1.printStackTrace();
			listener.onDownLoadProgress(Config.FTP_CONNECT_FAIL, 0, null);
			return;
		}
		ftpClient.enterLocalPassiveMode();
		// 先判断服务器文件是否存在
		FTPFile[] files = ftpClient.listFiles(new String(serverPath.getBytes("UTF-8")));
		if (files.length == 0) {
			listener.onDownLoadProgress(Config.FTP_FILE_NOTEXISTS, 0, null);
			return;
		}
		//创建本地文件夹
		File mkFile = new File(localPath);
		if (!mkFile.exists()) {
		boolean b=	mkFile.mkdirs();
			LogUtils.i(TAG,"创建下载文件"+b);
		}

		localPath = localPath +"/"+ fileName;
		// 接着判断下载的文件是否能断点下载
		long serverSize = files[0].getSize(); // 获取远程文件的长度
		File localFile = new File(localPath);
		long localSize = 0;
		if (localFile.exists()) {
			localSize = localFile.length(); // 如果本地文件存在，获取本地文件的长度
			if (localSize >= serverSize) {
				File file = new File(localPath);
				file.delete();
				localSize=0;
			}
		}
		
		// 进度
		long step = serverSize / 100;
		long process = 0;
		long currentSize = 0;
		// 开始准备下载文件
		OutputStream out = new FileOutputStream(localFile, true);
		ftpClient.setRestartOffset(localSize);
		ftpClient.enterLocalPassiveMode();
		InputStream input = ftpClient.retrieveFileStream(serverPath);
		byte[] b = new byte[1024];
		int length = 0;
		while ((length = input.read(b)) != -1) {
			out.write(b, 0, length);
			currentSize = currentSize + length;

			/*start*/
			long currTime=System.currentTimeMillis();

			if (currTime-mLasttime>=1000){
				mLasttime = System.currentTimeMillis();
				long  size=	(currentSize-mLastSize)/1024;
				if (mSpeedListener!=null){
					mSpeedListener.currentSpeed(size);
				}
				mLastSize = currentSize;
			}

			/*end*/

			if (currentSize / step != process) {
				process = currentSize / step;
				if (process % 1== 0) {  //每隔%5的进度返回一次
					listener.onDownLoadProgress(Config.FTP_DOWN_LOADING, process, null);
				}
			}
		}
		out.flush();
		out.close();
		input.close();
		
		// 此方法是来确保流处理完毕，如果没有此方法，可能会造成现程序死掉
		if (ftpClient.completePendingCommand()) {
			listener.onDownLoadProgress(Config.FTP_DOWN_SUCCESS, 0, new File(localPath));
		} else {
			listener.onDownLoadProgress(Config.FTP_DOWN_FAIL, 0, null);
		}

		// 下载完成之后关闭连接
		this.closeConnect();
		listener.onDownLoadProgress(Config.FTP_DISCONNECT_SUCCESS, 0, null);

		return;
	}

	// -------------------------------------------------------文件删除方法------------------------------------------------

	/**
	 * 删除Ftp下的文件.
	 * 
	 * @param serverPath
	 *            Ftp目录及文件路径
	 * @param listener
	 *            监听器
	 * @throws IOException
	 */
	public void deleteSingleFile(String serverPath, DeleteFileProgressListener listener)
			throws Exception {
		// 打开FTP服务
		try {
			this.openConnect();
			listener.onDeleteProgress(Config.FTP_CONNECT_SUCCESSS);
		} catch (IOException e1) {
			e1.printStackTrace();
			listener.onDeleteProgress(Config.FTP_CONNECT_FAIL);
			return;
		}

		// 先判断服务器文件是否存在
		FTPFile[] files = ftpClient.listFiles(serverPath);
		if (files.length == 0) {
			listener.onDeleteProgress(Config.FTP_FILE_NOTEXISTS);
			return;
		}
		
		//进行删除操作
		boolean flag = true;
		flag = ftpClient.deleteFile(serverPath);
		if (flag) {
			listener.onDeleteProgress(Config.FTP_DELETEFILE_SUCCESS);
		} else {
			listener.onDeleteProgress(Config.FTP_DELETEFILE_FAIL);
		}
		
		// 删除完成之后关闭连接
		this.closeConnect();
		listener.onDeleteProgress(Config.FTP_DISCONNECT_SUCCESS);
		
		return;
	}

	// -------------------------------------------------------打开关闭连接------------------------------------------------

	/**
	 * 打开FTP服务.
	 * 
	 * @throws IOException
	 */
	public void openConnect() throws IOException {
		// 中文转码
		ftpClient.setControlEncoding("UTF-8");
		int reply; // 服务器响应值
		// 连接至服务器
		if (hostName==null ||hostName.length()==0){
			ToastUtils.makeText(UIUtils.getContext(),"ftp主机不存在");
			return;
		}
		ftpClient.connect(hostName, serverPort);
		LogUtils.i(TAG,"honstname"+hostName+"::serverPort"+serverPort);

		// 获取响应值
		reply = ftpClient.getReplyCode();
		if (!FTPReply.isPositiveCompletion(reply)) {
			// 连接出错,断开连接
			ftpClient.disconnect();
			throw new IOException("connect fail: " + reply);
		}
		if (userName==null || userName.length()==0 ||password==null ||password.length()==0){
			ToastUtils.makeText(UIUtils.getContext(),"ftp登录账户不存在");
			return;
		}
		// 登录到服务器
		ftpClient.login(userName, password);
		// 获取响应值
		reply = ftpClient.getReplyCode();
		//ftpClient.enterLocalPassiveMode();
		if (!FTPReply.isPositiveCompletion(reply)) {
			// 断开连接
			ftpClient.disconnect();
			throw new IOException("connect fail: " + reply);

		} else {
			// 获取登录信息
			FTPClientConfig config = new FTPClientConfig(ftpClient
					.getSystemType().split(" ")[0]);
			config.setServerLanguageCode("zh");
			ftpClient.configure(config);
			// 使用被动模式设为默认
			ftpClient.enterLocalPassiveMode();
			// 二进制文件支持
			ftpClient
					.setFileType(org.apache.commons.net.ftp.FTP.BINARY_FILE_TYPE);
		}
	}

	/**
	 * 关闭FTP服务.
	 * 
	 * @throws IOException
	 */
	public void closeConnect() throws IOException {
		if (ftpClient != null) {
			// 退出FTP
			ftpClient.logout();
			// 断开连接
			ftpClient.disconnect();

		}
	}

	// ---------------------------------------------------上传、下载、删除监听---------------------------------------------
	
	/*
	 * 上传进度监听
	 */
	public interface UploadProgressListener {
		public void onUploadProgress(String currentStep, long uploadSize, File file);
	}

	/*
	 * 下载进度监听
	 */
	public interface DownLoadProgressListener {
		public void onDownLoadProgress(String currentStep, long downProcess, File file);
	}

	/*
	 * 文件删除监听
	 */
	public interface DeleteFileProgressListener {
		public void onDeleteProgress(String currentStep);
	}


	//统计瞬时速度
	private SpeedListener mSpeedListener;
	public interface SpeedListener{
		void currentSpeed(long size);
	}
	public void setSpeedListener(SpeedListener speedListener){
		this.mSpeedListener=speedListener;
	}
}
